package service

import (
	"fabric-explorer/dao"
	"fabric-explorer/entity"
	"fabric-explorer/tools"
	"fabric-explorer/websocket"
	"fmt"

	"github.com/gin-gonic/gin"
	"github.com/golang/protobuf/proto"
	"github.com/hyperledger/fabric-protos-go/common"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo/options"
)

//初始化区块数据
func InitBlockData() {
	ledgerClient, sdk, err := tools.GetLedgerClient()
	defer sdk.Close()
	if err != nil {
		fmt.Println(err)
		return
	}
	response, err := ledgerClient.QueryInfo()
	if err != nil {
		fmt.Println(err)
		return
	}
	//区块基本信息
	blockHeight := response.BCI.Height
	//遍历所有的区块
	//for i := blockHeight; i > 0; i-- {
	for i := uint64(0); i < blockHeight; i++ {

		commonBlock, err := ledgerClient.QueryBlock(i)
		if err != nil {
			fmt.Println(err)
			return
		}
		block := commonBlockToBlock(commonBlock)
		dao.InsertBlock(*block)
		dao.InsertBlockData(entity.BlockData{
			Num:  block.Num,
			Data: block.Data,
		})
	}
	fmt.Printf("Block_List 初始化成功\n")
}

//更新block数据
func UpdateBlockData() {
	ledgerClient, sdk, err := tools.GetLedgerClient()
	defer sdk.Close()
	if err != nil {
		fmt.Println(err)
		return
	}
	response, err := ledgerClient.QueryInfo()
	if err != nil {
		fmt.Println(err)
		return
	}
	//区块高度
	blockHeight := response.BCI.Height
	blockListlength := dao.GetBlockNum(bson.D{})
	//如果区块比blockList高，则更新
	if blockHeight > uint64(blockListlength) {
		//更新
		for i := uint64(blockListlength); i < blockHeight; i++ {
			commonBlock, err := ledgerClient.QueryBlock(i)
			if err != nil {
				fmt.Println(err)
				return
			}
			block := commonBlockToBlock(commonBlock)
			dao.InsertBlock(*block)
			blockData := entity.BlockData{
				Num:  block.Num,
				Data: block.Data,
			}
			dao.InsertBlockData(blockData)
			//更新交易数据
			transactionList := GetTransactionFromBlock(blockData)
			for _, t := range transactionList {
				dao.InsertTransaction(t)
			}
		}
	}
	//更新链码数据
	//InitChaincodeList()
	fmt.Printf("-----区块链block和transaction数据更新成功----")
	fmt.Printf("Block_List 高度: %v\n", dao.GetBlockNum(bson.D{}))
	//发送websocket消息通知前台更新数据
	go websocket.SendMsg(gin.H{"msg": "new block create", "update": true})
}

//commonBlock转block
func commonBlockToBlock(commonBlock *common.Block) *entity.Block {
	block := entity.Block{}

	//原始数据
	block.DataHash = fmt.Sprintf("%x", commonBlock.Header.DataHash)
	block.Num = commonBlock.Header.Number
	block.PreviousHash = fmt.Sprintf("%x", commonBlock.Header.PreviousHash)
	block.Size = commonBlock.XXX_Size()

	//计算当前区块hash
	currenthash := tools.BlockHeaderHash(commonBlock.Header)
	block.BlockHash = fmt.Sprintf("%x", currenthash)
	//取详细数据
	block.Data = commonBlock.Data.GetData()
	for _, v := range commonBlock.Data.GetData() {
		var envelope common.Envelope

		if err := proto.Unmarshal(v, &envelope); err != nil {
			fmt.Println(err)
			return nil
		}

		//获得payload
		var payload common.Payload
		err := proto.Unmarshal(envelope.GetPayload(), &payload)
		if err != nil {
			fmt.Println(err)
			return nil
		}

		//获得channelHeader
		var channelHeader common.ChannelHeader
		err = proto.Unmarshal(payload.Header.GetChannelHeader(), &channelHeader)
		if err != nil {
			fmt.Println(err)
			return nil
		}
		block.ChannelId = channelHeader.ChannelId
		block.TxId = append(block.TxId, channelHeader.TxId)
		block.Timestamp = channelHeader.Timestamp.AsTime().UnixMilli()
	}
	return &block
}

//获得所有的block
func GetAllBlock() []entity.Block {
	return dao.FindBlockList(bson.D{})
}

//获得的blockList
func FindBlockList(selecter bson.D) []entity.Block {
	return dao.FindBlockList(selecter)
}

//删除所有的block数据
func DeleteAllBlock() {
	dao.DeleteBlock(bson.D{})
}

//获得所有的block的数量
func GetBlockNum(selecter bson.D) int64 {
	return dao.GetBlockNum(selecter)
}

//查询一个block
func FindBlockOne(selecter bson.D) entity.Block {
	return dao.FindBlockOne(selecter)
}

//查询page
func FindBlockListPage(selecter bson.D, options *options.FindOptions) []entity.Block {
	return dao.FindBlockListPage(selecter, options)
}
